package sale.wxb.loveshopping.security;

import cn.hutool.json.JSONUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import sale.wxb.loveshopping.constant.RedisConst;
import sale.wxb.loveshopping.entity.bo.UserTokenRedisBo;
import sale.wxb.loveshopping.entity.yml.YmlConfigAntMatchers;
import sale.wxb.loveshopping.entity.yml.YmlConfigAuth;
import sale.wxb.loveshopping.utils.RedisUtil;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Component
public class TokenAuthenticationFilter extends OncePerRequestFilter {
    @Autowired
    private YmlConfigAuth ymlConfigAuth;
    @Autowired
    private YmlConfigAntMatchers ymlConfigAntMatchers;
    @Autowired
    private RedisUtil redisUtil;
    private final AntPathMatcher antPathMatcher = new AntPathMatcher();

    /**
     * URL ANT路径匹配
     * @param request HttpServletRequest
     * @return boolean
     */
    private boolean urlMatcher(HttpServletRequest request) {
        List<String> paths = new ArrayList<>();
        paths.addAll(ymlConfigAntMatchers.getAnonymous());
        paths.addAll(ymlConfigAntMatchers.getPermitAll());

        for (String path : paths) {
            if (antPathMatcher.match(path, request.getServletPath())) {
                // 任意匹配上一个就直接返回
                return true;
            }
        }

        return false;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 匹配是否需要授权的路由
        String path = ymlConfigAntMatchers.getAuthenticated().stream().filter(x -> antPathMatcher.match(x, request.getServletPath())).findFirst().orElse(null);
        // 匹配是否在过滤白名单中，是则直接放行给security处理
        if (!StringUtils.hasText(path)) {
            if (urlMatcher(request)) {
                filterChain.doFilter(request, response);
                return;
            }
        }

        String token = request.getHeader(ymlConfigAuth.getHeaderTokenKey());

        if (!StringUtils.hasText(token)) {
            filterChain.doFilter(request, response);
            return;
        }

        // 查询是否存在redis 未登录
        String redisJson = (String) redisUtil.get(redisUtil.getKey(RedisConst.TOKEN_USER, token));

        if (!StringUtils.hasText(redisJson)) {
            filterChain.doFilter(request, response);
            return;
        }

        UserTokenRedisBo userTokenRedisBo = JSONUtil.toBean(redisJson, UserTokenRedisBo.class);
        UserDetailEntity userDetailEntity = new UserDetailEntity(userTokenRedisBo.getSysUser());
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetailEntity, null, null);
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        filterChain.doFilter(request, response);
    }
}
